/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef TRI_ANIMATE_H_
#define TRI_ANIMATE_H_

#include "utils.h"
#include "vector.h"
#include "timer.h"

namespace tri {

/**
 * Calculate the midpoint value of an linear animating variable.
 * 
 * @param start_value Initail value
 * @param end_value . Target value
 * @param timer : TProgressTimer instance (in TIMER_TYPE setting)
 * @current_value. Current value.
 */
float animateLinear(const float& start_value, const float& end_value,
        TProgressTimer& timer, const float& current_value);
float animateExp(const float& start_value, const float& end_value,
        TProgressTimer& timer, const float& current_value);

#define LINEAR_ANIMATE &animateLinear
#define EXP_ANIMATE &animateExp

class TAniVar {
public:
    TAniVar();
    virtual ~TAniVar();
	
	/**
	 * Is this TVector still animating
	 */ 
	bool isAnimating();

    /**
     * Get the internally stored value
     * 
     * @return Current value
     */
    float getValue();

    /**
     * Set the instance value
     * 
     *@param v New Value
     */
    void setValue(const float& v);

    /**
     * Set the value to animate to.
     * 
     * @param v : target value
     */
    void setTargetValue(const float& v);

    /**
     * Set the value to animate to.
     * 
     * @param v : target value
     * @param t : duration of animation in seconds.
     */
    void setTargetValue(const float& v, const float& t);
    
    /**
     * Get the target value
     */
    float getTargetValue();

    /**
     * Set the animator. Values are LINEAR_ANIMATE or AXP_ANIMATE
     */
    void setAnimator(float (*ani)(const float&,
            const float&,
            tri::TProgressTimer&,
            const float&));

    /**
     * Add a value to the TVector
     */

    void add(float& v);
    void mult(float& v);
    
    
private:
    /**
     * Internally stored value
     */
    float value;
    TProgressTimer timer;
    float end_val;
    float start_val;
    float (*animator)(const float&, const float&, TProgressTimer&,
            const float&);

};

class TAniVector {
public:
    TAniVector();
    TAniVector(const float& x, const float& y, const float& z);
    TAniVector(const float* v);
    virtual ~TAniVector();
	
	/**
	 * Is this TVector still animating
	 */ 
	bool isAnimating();

    /**
     * Get the internally stored value
     * 
     * @param storage for 3 doubles
     */
    void getValue(float * v);
    void getValue(TVector *v);
    tri::TVector getValue();
    
    
    /**
     * Get the Target value
     */
    tri::TVector getTargetValue();

    /**
     * Get the x value; 
     */
    float getX();

    /**
     * Get the y value; 
     */
    float getY();

    /**
     * Get the z value; 
     */
    float getZ();

    /**
     * Set the instance value
     * 
     *@param x X Value
     *@param y Y Value
     *@param z Z Value
     */
    void setValue(const float& x, const float& y, const float& z);
    void setValue(const TVector * v);
    void setValue(tri::TVector v);
    /**
     * Set the instance value
     * 
     *@param v array of 3 doubles (x,y,z)
     */
    void setValue(const float * v);

    /**
     * Set the X value
     */
    void setX(const float& v);

    /**
     * Set the Y value
     */
    void setY(const float& v);

    /**
     * Set the Z value
     */
    void setZ(const float& v);

    /**
     * Set the instance value
     * 
     *@param v array of 3 doubles (x,y,z)
     */
    void setTargetValue(const float *v, const float& t = 1.0);
    void setTargetValue(const TVector *v, const float& t = 1.0);
    /**
     * Set the instance value
     * 
     *@param x X Value
     *@param y Y Value
     *@param z Z Value
     */
    void setTargetValue(const float& x, const float& y, const float& z,
            const float& t = 1.0);

    /**
     * Target values for X component
     * 
     * @param v Value
     * @param t : optional aniamtion time
     */
    void setTargetValueX(const float &value, const float& t = 1.0);

    /**
     * Target values for Y component
     * 
     * @param v Value
     * @param t : optional aniamtion time
     */
    void setTargetValueY(const float &value, const float& t = 1.0);

    /**
     * Target values for Z component
     * 
     * @param v Value
     * @param t : optional aniamtion time
     */
    void setTargetValueZ(const float &value, const float& t = 1.0);

    /**
     * Set the animator. Values are LINEAR_ANIMATE or AXP_ANIMATE
     */
    void setAnimator(float (*ani)(const float&,
            const float&,
            tri::TProgressTimer&,
            const float&));

    /**
     * Add a value to the TVector
     */
    void add(float x, float y, float z);
    
    tri::TAniVector& operator=(const tri::TVector &v);

private:
    TAniVar x;
    TAniVar y;
    TAniVar z;
};

}

#endif /*ANIMATE_H_*/
